define(["core/exception", "extensions/array", "//cdnjs.cloudflare.com/ajax/libs/openlayers/2.12/OpenLayers.min.js"], function (Exception) {
    "use strict";

    function Map() {
        if (document.getElementById('geo') == undefined) throw new Exception("geo is not defined");

        console.log('models/map.js. constructor.');   

        var apiKey = "AqTGBsziZHIJYYxgivLBf0hVdrAk9mWO5cQcb8Yux8sW5M8c8opEC2lZqKR1ZZXf";

        this.map = new OpenLayers.Map('geo');

        var road = new OpenLayers.Layer.Bing({
            key: apiKey,
            type: "Road",
            // custom metadata parameter to request the new map style - only useful
            // before May 1st, 2011
            metadataParams: { mapVersion: "v1" }
        });
        var aerial = new OpenLayers.Layer.Bing({
            key: apiKey,
            type: "Aerial"
        });
        var hybrid = new OpenLayers.Layer.Bing({
            key: apiKey,
            type: "AerialWithLabels",
            name: "Bing Aerial With Labels"
        });

        this.markers = new OpenLayers.Layer.Markers("Markers");
        console.log('models/map.js. constructor. markers created.'); 
          
        this.routes = new OpenLayers.Layer.Vector("Routes"); 
        console.log('models/map.js. constructor. routes created.'); 

        this.map.addLayers([road, aerial, hybrid, this.markers, this.routes]);
        this.map.addControl(new OpenLayers.Control.LayerSwitcher());

        console.log('models/map.js. constructor. LayerSwitcher created.'); 

        var zoom = this.map.getZoomForResolution(76.43702827453613);

        this.epsg4326 =  new OpenLayers.Projection("EPSG:4326"); //WGS 1984 projection
        this.projectTo = this.map.getProjectionObject();

        this.map.setCenter(new OpenLayers.LonLat(2.35222, 48.856614).transform(this.epsg4326, this.projectTo), zoom);    
        
        console.log('models/map.js. instantiated.');   
    };

    Map.prototype = {
        constructor: Map,
        addMarker: function (position) {
            console.log('model/map.js. addMarker: ' + JSON.stringify(position));
            var size = new OpenLayers.Size(21, 25);
            var offset = new OpenLayers.Pixel(-(size.w / 2), -size.h);

            var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset);
            var lonlat = new OpenLayers.LonLat(position.longitude, position.latitude).transform(this.epsg4326, this.projectTo);

            var marker = new OpenLayers.Marker(lonlat, icon);
            marker.id = position.id; //inject id for identify marker
            this.markers.addMarker(marker);
            return marker;
        },
        removeMarker: function (position) {
            console.log('model/map.js. removeMarker: ' + JSON.stringify(position));
            var marker = this.getMarker(position.id);
            if (marker) this.markers.removeMarker(marker);
        },
        getMarker: function (id) {
            return this.markers.markers.filter(function (element) { return element.id == id; }).first();
        },
        updateMarker: function (position) {
            console.log('model/map.js. updateMarker: ' + JSON.stringify(position));
            var marker = this.getMarker(position.id);
            if (marker == undefined)
                marker = this.addMarker(position);
            else
                marker.lonlat = new OpenLayers.LonLat(position.longitude, position.latitude).transform(this.epsg4326, this.projectTo);
            return marker;
        },
        panTo: function (marker) {
            console.log('model/map.js. panTo: ' + JSON.stringify(marker.lonlat));
            this.map.panTo(marker.lonlat);
        },
        drawRoute: function (latLngs) {
            this.route.setLatLngs(latLngs);
        }

    };
    console.log('model/map.js');
    return new Map();
});